﻿using System;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using RHD.Common.Web.Utility.Extensions;
using RHD.Common.Web.Components.AutoComplete;
using RHD.Web.Infrastructure;

namespace RHD.Common.Web.Components {
	public static class AutoCompleteExtension {
		public static MvcHtmlString AutoComplete(this HtmlHelper htmlHelper, string id, object value = null, object text = null, Action<AutoCompleteBuilder> optionsHandle = null, object htmlAttributes = null) {
			return AutoComplete(htmlHelper, id, value, null, text, optionsHandle, null, htmlAttributes);
		}

		public static MvcHtmlString AutoCompleteFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expressionValue, Action<AutoCompleteBuilder> optionsHandle = null, object htmlAttributes = null) {
			ModelMetadata model = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expressionValue, htmlHelper.ViewData);
			return AutoComplete(htmlHelper, ExpressionHelper.GetExpressionText(expressionValue), model.Model, null, null, optionsHandle, model, htmlAttributes);
		}

		public static MvcHtmlString AutoCompleteFor<TModel, TProperty, TPropertyText>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expressionValue, Expression<Func<TModel, TPropertyText>> expressionText, Action<AutoCompleteBuilder> optionsHandle = null, object htmlAttributes = null) {
			ModelMetadata model = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expressionValue, htmlHelper.ViewData);
			ModelMetadata modelText = ModelMetadata.FromLambdaExpression<TModel, TPropertyText>(expressionText, htmlHelper.ViewData);
			return AutoComplete(htmlHelper, ExpressionHelper.GetExpressionText(expressionValue), model.Model, ExpressionHelper.GetExpressionText(expressionText), modelText.Model, optionsHandle, model, htmlAttributes);
		}

		private static MvcHtmlString AutoComplete(this HtmlHelper htmlHelper, string id, object value = null, string idText = null, object text = null, Action<AutoCompleteBuilder> optionsHandle = null, ModelMetadata modelMetadata = null, object htmlAttributes = null) {
			AutoCompleteBuilder options = new AutoCompleteBuilder();
			if (optionsHandle != null)
				optionsHandle(options);

			if (string.IsNullOrEmpty(idText))
				idText = string.Format("{0}_txt", id);

			TagBuilder hidden = new TagBuilder("input");
			hidden.GenerateId(id);
			hidden.Attributes["name"] = htmlHelper.GetFullHtmlFieldName(id);
			hidden.Attributes["type"] = "hidden";
			id = hidden.Attributes["id"];

			if (value != null)
				hidden.Attributes["value"] = value.ToString();

			TagBuilder input = new TagBuilder("input");
			input.GenerateId(idText);
			input.Attributes["name"] = htmlHelper.GetFullHtmlFieldName(idText);
			input.Attributes["type"] = "text";
			if (htmlAttributes != null)
				input.MergeAttributes<string, object>(new RouteValueDictionary(htmlAttributes));

			if (text != null)
				input.Attributes["value"] = text.ToString();

			MvcHtmlString validation = MvcHtmlString.Empty;
			if (modelMetadata != null) {
				hidden.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(modelMetadata.PropertyName, modelMetadata));
				validation = ValidationExtensions.ValidationMessage(htmlHelper, modelMetadata.PropertyName);
			}

			RegisterScript(htmlHelper, id, options);
			return new MvcHtmlString(string.Format("{0}{1}{2}", hidden, input, validation));
		}

		private static void RegisterScript(HtmlHelper htmlHelper, string id, AutoCompleteBuilder options) {
			StringBuilder option = new StringBuilder();
			option.AppendFormat("minLength: {0},", options.minLength);
			if (options.source != null && options.source.Count > 0) {
				string source = string.Empty;
				foreach (SelectListItem item in options.source)
					source += string.Format("{{Text: '{0}', Value:'{1}'}}{2}", item.Text, item.Value, ((options.source.IndexOf(item) + 1) != options.source.Count ? ",\n" : string.Empty));
				option.AppendFormat("source: [{0}],", source);
			}
			if (!string.IsNullOrEmpty(options.urlAction))
				option.AppendFormat("urlAction: '{0}',", options.urlAction);
			if (!string.IsNullOrEmpty(options.fnPrepareParameters))
				option.AppendFormat("fnPrepareParameters: '{0}',", options.fnPrepareParameters);
			option.AppendFormat("cache: {0}", options.cache ? "true" : "false");

			htmlHelper.AddScript(string.Format("$('#{0}')._AutoComplete({{{1}}});", id, option));
		}
	}
}